package com.yummy.cloud.gateway.manage.service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.support.Configurable;
import org.springframework.stereotype.Service;

import com.yummy.cloud.gateway.manage.dto.ConfigurableMetadata;

@Service
public class InfrastructureService implements InitializingBean{
	
	@Autowired
	private List<RoutePredicateFactory> routePredicateFactorys;
	
	private Map<String,RoutePredicateFactory> predicateFactoryMap;
	private Map<String,GatewayFilterFactory> filterFactoryMap;
	
	@Autowired
	private List<GatewayFilterFactory> gatewayFilterFactories;

	public List<ConfigurableMetadata> getPredicateMetadatas() {
		return routePredicateFactorys.stream().map(predicate -> {
			ConfigurableMetadata metadata = new ConfigurableMetadata();
			metadata.setName(predicate.name());
			metadata.setArgNames(getArgNames(predicate));
			return metadata;
		}).collect(Collectors.toList());
	}
	
	public List<ConfigurableMetadata> getFilterMetadatas() {
		return gatewayFilterFactories.stream().map(filter -> {
			ConfigurableMetadata metadata = new ConfigurableMetadata();
			metadata.setName(filter.name());
			metadata.setArgNames(getArgNames(filter));
			return metadata;
		}).collect(Collectors.toList());
	}

	private List<String> getArgNames(Configurable configurable) {
		Class configClass = configurable.getConfigClass();
		Field[] fields = configClass.getDeclaredFields();
		List<String> list = new ArrayList<>();
		for(Field field : fields) {
			list.add(field.getName());
		}
		return list;
	}


	public Map<String,RoutePredicateFactory> getPredicateFactoryMap() {
		return predicateFactoryMap;
	}

	public void setPredicateFactoryMap(Map<String,RoutePredicateFactory> predicateFactoryMap) {
		this.predicateFactoryMap = predicateFactoryMap;
	}

	public Map<String,GatewayFilterFactory> getFilterFactoryMap() {
		return filterFactoryMap;
	}

	public void setFilterFactoryMap(Map<String,GatewayFilterFactory> filterFactoryMap) {
		this.filterFactoryMap = filterFactoryMap;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		predicateFactoryMap = new HashMap<>();
		routePredicateFactorys.stream().forEach(p -> {
			predicateFactoryMap.put(p.name(), p);
		});
		filterFactoryMap = new HashMap<>();
		gatewayFilterFactories.stream().forEach(f -> {
			filterFactoryMap.put(f.name(), f);
		});
	}

	public static class InnerConfigClass{
		private String prefix;
		private Class configClass;
		public String getPrefix() {
			return prefix;
		}
		public void setPrefix(String prefix) {
			this.prefix = prefix;
		}
		public Class getConfigClass() {
			return configClass;
		}
		public void setConfigClass(Class configClass) {
			this.configClass = configClass;
		}
		
	}
}
